@octamap/mesa
Mesa is a build-time HTML component engine that allows you to write reusable, declarative HTML components with scoped CSS and dynamic attributes — without requiring runtime JavaScript to render them.
Whether you're building a static website, a micro-frontend architecture, or HTML-first website development, Mesa keeps your pages lightweight, SEO-friendly, and blazing fast.
Mesa allows you to:
- Write reusable HTML components.
- Use them in other HTML files.
- Automatically handle props, dynamic attributes, and scoped styles at build time.
No need for large runtimes for reactivity (such as Vue, React & Svelte)
Mesa is framework agnostic. Achive the same level of reactivity by pairing it up with somthing quick and lightweight like alpine.js or HTMX for ⚡️super quick hydration⚡️
Type completions & syntax highlighting is now supported through a brand new Mesa Visual Studio Code extension!!
Install Mesa VS Code Extension
This extension is really new. Please send any issues with the extension to extension@octamap.com
Define a reusable component in its own file:
<button class="close-button">
<svg>...</svg>
</button>
<style>
.close-button {
background: red;
color: white;
border: none;
padding: 8px 12px;
cursor: pointer;
}
</style>
- The
<button>
contains your markup. - The
<style>
block includes the scoped CSS.
In your main HTML file, simply use the <my-custom-button>
tag:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="component-styles.css">
</head>
<body>
<h1>Welcome to Mesa</h1>
<my-custom-button @click="exampleEvent"></my-custom-button>
</body>
</html>
Mesa compiles the above into:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="component-styles.css">
</head>
<body>
<h1>Welcome to Mesa</h1>
<button class="close-button" @click="exampleEvent">
<svg>...</svg>
</button>
</body>
</html>
.close-button {
background: red;
color: white;
border: none;
padding: 8px 12px;
cursor: pointer;
}
✅ Props and attributes are passed automatically.
✅ Styles are extracted and scoped correctly.
✅ No runtime rendering — everything happens at build time.
Pass attributes and dynamic bindings directly on the root element:
index.html
<my-custom-button @click="handleClick"></my-custom-button>
Build Output:
<button class="close-button" @click="handleClick">
<svg>...</svg>
</button>
✅ Events (@click
) and bindings (x-model
) are preserved and passed correctly.
If your component has an element marked as #default
, props are mapped automatically:
my-input.html
<div>
<input #default class="input-field" />
</div>
index.html
<my-input placeholder="Enter your email" x-model="email"></my-input>
Build Output:
<div>
<input class="input-field" placeholder="Enter your email" x-model="email" />
</div>
✅ Clean, predictable prop mapping.
Details
- The root element of the component is automatically the
#default
if no other element within the component has a#default
attribute
Map specific child elements to targets in your components:
my-card.html
<div class="card">
<h1 #title></h1>
<p #content></p>
</div>
index.html
<my-card>
<title>This is the Title</title>
<content>This is the Content</content>
</my-card>
Build Output:
<div class="card">
<h1>This is the Title</h1>
<p>This is the Content</p>
</div>
✅ Clear and intuitive named slot-like behavior.
Each component’s styles are:
- Scoped to their usage (avoiding global CSS pollution).
- Automatically extracted into
component-styles.css
.
✅ Styles only load when they’re needed.
Mesa supports nested components seamlessly:
nested-component.html
<div class="nested">
<inner-component></inner-component>
</div>
index.html
<nested-component></nested-component>
Mesa recursively processes inner components during the build phase.
✅ Fully recursive parsing and transformation.
Setup a new mesa project by running the command below, this sets you up with a sample website:
npx @octamap/create-mesa@latest project-name
npm install @octamap/mesa --save-dev
Update your vite.config.ts
:
import { defineConfig } from 'vite';
import { Mesa } from '@octamap/mesa';
export default defineConfig({
plugins: [
Mesa({
'my-custom-button': './src/components/my-custom-button.html',
'my-card': './src/components/my-card.html'
})
]
});
npm run dev
✅ Enjoy live-reloading and build-time transformations.
npm run build
✅ Your components are compiled, styles extracted, and everything is optimized.
Svelte SSG has been the wholy grail of quick websites. With Mesa you achive this but even quicker.
-
SvelteKit SSG hydration involves loading the Svelte runtime and then essentially "rebuilding" the page’s structure by mapping pre-rendered HTML to its components.
-
Mesa achieves the same level of interactivity by allowing you to use lightweight frameworks like Alpine.js or HTMX, which operate directly on the DOM. These frameworks don’t need to rebuild the page’s structure—they simply bind functionality to the already-rendered HTML.
Feature | SvelteKit (SSG) | Mesa + alpine.js |
---|---|---|
Initial HTML Load | Instant | Instant |
JavaScript Payload | Medium (slightly larger) | Small (lightweight) |
Hydration Speed | Slightly Slower | Faster (no hydration) |
Reactivity Setup Time | Fast, but hydration required | Very Fast |
In larger projects or when working with shared component libraries, managing all your component mappings directly inside vite.config.ts
can become cumbersome. Mesa allows you to define components in an external JavaScript or TypeScript file using the components
function.
This approach ensures better separation of concerns, easier reusability, and improved readability.
Create a file to define your components, for example:
import { components } from "@octamap/mesa";
// Use import.meta.url to resolve absolute paths to component files
const OctamapHtmlComponents = components(import.meta.url, {
"icon-field": "./src/icon-field.html",
"close-button": "./src/close-button.html",
"back-button": "./src/back-button.html",
"head-defaults": "./src/head-defaults.html",
});
export { OctamapHtmlComponents };
The import.meta.url
ensures that Mesa can resolve absolute paths to your HTML component files. Without it, the plugin might struggle to correctly locate your component files, especially when working across different environments or build pipelines.
Import your component configuration into vite.config.ts
:
import { defineConfig } from 'vite';
import { Mesa } from '@octamap/mesa';
import { OctamapHtmlComponents } from './components';
export default defineConfig({
plugins: [
Mesa(OctamapHtmlComponents)
]
});
- The
components
function maps component names (icon-field
,close-button
) to their respective HTML files (icon-field.html
,close-button.html
). -
import.meta.url
ensures absolute paths are resolved correctly at runtime. -
vite.config.ts
references these mappings viaOctamapHtmlComponents
.
This approach keeps your vite.config.ts
clean and focused while centralizing component definitions in a separate file.
✅ Improved Maintainability: Component mappings are easier to update and manage in one dedicated file.
✅ Reusability: The configuration can be reused across different projects or environments.
✅ Scalability: Large projects with hundreds of components are easier to organize.
✅ Clear Separation: vite.config.ts
remains focused on build configuration.
/src
/components
icon-field.html
close-button.html
back-button.html
head-defaults.html
/scripts
components.ts <-- Define component mappings here
vite.config.ts <-- Reference the mappings
Mesa now supports bulk registration of .html
or .svg
components from an entire folder using the folder
function. This makes it incredibly easy to manage and include multiple components without manually defining each one in your configuration.
You can register all .html
and .svg
components in a folder using the folder
utility:
vite.config.ts
import { defineConfig } from 'vite';
import { Mesa, folder } from '@octamap/mesa';
import { OctamapHtmlComponents } from './components';
export default defineConfig({
plugins: [
Mesa({
...OctamapHtmlComponents,
...folder("./icons") // Registers all components in the ./icons folder
}),
],
});
✅ The folder
function scans the ./icons
directory and registers all .html
and .svg
files as components.
✅ Nested folders are supported, and components are named based on their folder structure.
Your project might have a folder structure like this:
/icons
letter-notification.svg
/another-folder
profile-icon.svg
After registering the folder, you can use the components directly in your HTML:
index.html
<div>
<div class="check-inbox-page">
<letter-notification height="60px"></letter-notification>
<another-folder-profile-icon></another-folder-profile-icon>
</div>
</div>
✅ Automatic Naming:
-
letter-notification.svg
→<letter-notification>
-
another-folder/profile-icon.svg
→<another-folder-profile-icon>
✅ Scoped Naming: Nested folder structures are preserved in the component names to avoid conflicts.
- The
folder
function scans the specified directory. - Each
.html
and.svg
file is registered as a Mesa component. - Nested files are automatically prefixed with their folder names.
Example Naming Convention:
-
icons/alert.svg
→<alert>
-
icons/notifications/alert.svg
→<notifications-alert>
This ensures unique and collision-free component names.
With folder
, managing and scaling your components becomes effortless. Say goodbye to repetitive mappings and enjoy clean, intuitive configurations. 🚀✨
Here's an illustrative section explaining how Mesa handles scoped styles for components and ensures they are appropriately applied regardless of where the component is used:
Mesa ensures scoped styles are applied consistently across your components, whether they're used in a single page or multiple pages.
First, define your reusable component with its styles.
📂 letter-notification.svg
<svg>
..
</svg>
📂 check-inbox.html
<div>
<div class="check-inbox-page">
<letter-notification height="60px"></letter-notification>
</div>
</div>
<style>
.check-inbox-page {
height: 100px;
width: 200px;
}
</style>
When the component is used in a dedicated page, Mesa extracts and consolidates its styles into a global stylesheet (component-styles.css
).
📂 index.html
<body>
<check-inbox></check-inbox>
</body>
🔄 Build Output:
<head>
<link rel="stylesheet" href="/component-styles.css">
</head>
<body>
<div class="check-inbox-page">
<svg> .. </svg>
</div>
</body>
📂 component-styles.css
.check-inbox-page {
height: 100px;
width: 200px;
}
✅ Global styles ensure optimized loading for dedicated pages.
When the same component is used outside of its primary context (e.g., some-page.html
), Mesa intelligently inlines the required styles to prevent missing styles or dependency on global CSS.
📂 some-page.html
<div>
<check-inbox></check-inbox>
</div>
🔄 Build Output:
<div>
<style>
.check-inbox-page {
height: 100px;
width: 200px;
}
</style>
<div class="check-inbox-page">
<svg> .. </svg>
</div>
</div>
✅ Inline styles guarantee isolation and ensure the component renders consistently even without global styles.
In this example, we'll explore how Mesa enables seamless integration between separate packages for SVG icons and web components, allowing clean, reusable, and optimized component architecture.
We have two npm packages:
- oicon – A package containing SVG icons.
- components – A package containing reusable UI components, including one that uses icons from oicon.
oicon/
├── package.json
├── index.ts
└── src/
├── chevron-left.svg
├── checkmark.svg
import { folder } from '@octamap/mesa';
const OIconComponents = folder("./src/", {
importMetaUrl: import.meta.url, // Ensures Mesa resolves the correct paths
prefix: "oicon" // Enables usage as <oicon-chevron-left />
});
export { OIconComponents };
With this setup:
- Icons are accessible via
<oicon-chevron-left />
and<oicon-checkmark />
.
components/
├── package.json
├── index.ts
└── src/
└── back-button.html
<button class="top-left-back">
<oicon-chevron-left></oicon-chevron-left>
</button>
<style>
.top-left-back {
position: fixed;
left: 30px;
top: 30px;
--diameter: 55px;
height: var(--diameter);
width: var(--diameter);
display: flex;
align-items: center;
justify-content: center;
border-radius: 100em;
border: none;
outline: solid 1px var(--line-color);
background-color: white;
cursor: pointer;
}
</style>
Here:
- The Back Button component references
<oicon-chevron-left>
.
import { folder } from '@octamap/mesa';
const Components = folder("./src/", {
importMetaUrl: import.meta.url, // Correct path resolution
});
export { Components };
Now, let's integrate these packages into our Vite configuration.
import { defineConfig } from 'vite';
import { Mesa } from '@octamap/mesa';
import { OIconComponents } from '@your-package/oicon';
import { Components } from '@your-package/components';
export default defineConfig({
plugins: [
Mesa({
...OIconComponents,
...Components,
}),
],
});
Let's create a check-inbox.html
page.
<div class="check-inbox-page">
<back-button @click="closeCheckInbox()"></back-button>
</div>
<style>
.check-inbox-page {
display: flex;
flex-direction: column;
align-items: center;
position: absolute;
left: 0;
top: 0;
height: 100vh;
width: 100vw;
z-index: 100;
}
</style>
Mesa Handles:
-
Scoped Styles –
check-inbox-page
andtop-left-back
styles are scoped and applied correctly. -
Lazy Loading –
check-inbox.html
styles are inlined only when the page is loaded. -
Optimized Rendering – No unnecessary CSS in your
index.html
.
When a user navigates to check-inbox.html
:
- The router dynamically loads
check-inbox.html
. - Mesa inlines the required CSS for
.check-inbox-page
and.top-left-back
. - SVG content is embedded in the
<back-button>
component.
Resulting HTML:
<div class="check-inbox-page">
<button class="top-left-back" @click="closeCheckInbox()">
<svg viewBox="0 0 11 20" xmlns="http://www.w3.org/2000/svg">
<path d="M9.216,1.369l-7.847,8.627l7.847,8.628"
style="fill:#fff;stroke:currentColor;stroke-width:2.74px;"></path>
</svg>
</button>
</div>
<style>
.check-inbox-page {
display: flex;
flex-direction: column;
align-items: center;
position: absolute;
left: 0;
top: 0;
height: 100vh;
width: 100vw;
z-index: 100;
}
.top-left-back {
position: fixed;
left: 30px;
top: 30px;
--diameter: 55px;
height: var(--diameter);
width: var(--diameter);
display: flex;
align-items: center;
justify-content: center;
border-radius: 100em;
border: none;
outline: solid 1px var(--line-color);
background-color: white;
cursor: pointer;
}
</style>
-
Global Styles: For components used consistently across an entire page, styles are extracted into
component-styles.css
. - Inline Styles: When components are used in isolated contexts or ad-hoc pages, Mesa inlines the necessary styles directly.
✅ No CSS leakage across components.
✅ Optimal performance with minimal style duplication.
✅ Scoped styles ensure predictable rendering.
- Full Documentation: [Coming Soon]
- Starter Templates: [Coming Soon]
- Live Demo Projects: [Coming Soon]
✅ Static-first: Everything is rendered at build time.
✅ SEO-friendly: Full markup available to crawlers.
✅ No runtime overhead: Zero JavaScript parsing for rendering components.
✅ Scalable: Perfect for micro-frontends and component-based architectures.
✅ Framework-agnostic: Use with Alpine.js, HTMX, or vanilla JS.
- GitHub: https://github.com/octamap/mesa
Let’s redefine the way we build HTML components. 🚀